﻿using Devonline.AspNetCore;
using Devonline.Caching;
using Devonline.Communication.Abstractions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Devonline.Communication.Server;

/// <summary>
/// 通讯服务器扩展方法
/// </summary>
public static class ServerExtensions
{
    /// <summary>
    /// 根据配置, 添加通讯服务器
    /// </summary>
    /// <param name="services"></param>
    /// <param name="setting"></param>
    /// <returns></returns>
    public static IServiceCollection AddCommunicationServer(this IServiceCollection services, HostSetting? setting = default)
    {
        setting ??= new HostSetting();
        services.AddDistributedCache(setting.Cache);

        var signalRServerBuilder = services.AddSignalR(options =>
        {
            if (setting.HubOptions is not null)
            {
                if (setting.HubOptions.HandshakeTimeout.HasValue)
                {
                    options.HandshakeTimeout = TimeSpan.FromSeconds(setting.HubOptions.HandshakeTimeout.Value);
                }

                if (setting.HubOptions.KeepAliveInterval.HasValue)
                {
                    options.KeepAliveInterval = TimeSpan.FromSeconds(setting.HubOptions.KeepAliveInterval.Value);
                }

                if (setting.HubOptions.ClientTimeoutInterval.HasValue)
                {
                    options.ClientTimeoutInterval = TimeSpan.FromSeconds(setting.HubOptions.ClientTimeoutInterval.Value);
                }

                if (setting.HubOptions.SupportedProtocols is not null)
                {
                    options.SupportedProtocols = setting.HubOptions.SupportedProtocols;
                }

                if (setting.HubOptions.MaximumReceiveMessageSize.HasValue)
                {
                    options.MaximumReceiveMessageSize = setting.HubOptions.MaximumReceiveMessageSize;
                }

                if (setting.HubOptions.EnableDetailedErrors.HasValue)
                {
                    options.EnableDetailedErrors = setting.HubOptions.EnableDetailedErrors;
                }

                if (setting.HubOptions.StreamBufferCapacity.HasValue)
                {
                    options.StreamBufferCapacity = setting.HubOptions.StreamBufferCapacity;
                }

                if (setting.HubOptions.MaximumParallelInvocationsPerClient.HasValue)
                {
                    options.MaximumParallelInvocationsPerClient = setting.HubOptions.MaximumParallelInvocationsPerClient.Value;
                }
            }
        });

        _ = setting.TransportType switch
        {
            TransportType.Json => signalRServerBuilder.AddJsonProtocol(config => config.PayloadSerializerOptions = new System.Text.Json.JsonSerializerOptions().SetDefaultJsonSerializerOptions(setting)),
            TransportType.MessagePack => signalRServerBuilder.AddMessagePackProtocol(config => config.SerializerOptions = MessagePack.MessagePackSerializerOptions.Standard),
            _ => signalRServerBuilder.AddNewtonsoftJsonProtocol(config => config.PayloadSerializerSettings = new Newtonsoft.Json.JsonSerializerSettings().SetDefaultJsonSerializerSettings(setting))
        };

        return services;
    }

    /// <summary>
    /// 根据配置启用通讯器
    /// </summary>
    /// <param name="app"></param>
    /// <param name="setting"></param>
    public static void UseCommunicationServer(this WebApplication app, HostSetting? setting = default)
    {
        setting ??= new HostSetting();
        if (!string.IsNullOrWhiteSpace(setting.ApplicationDbContext))
        {
            app.MapHub<PersistentMessageServer>(setting.Host, options => options.SetServerOptions(setting));
        }
        else
        {
            app.MapHub<MessageServer>(setting.Host, options => options.SetServerOptions(setting));
        }

        app.Services.GetRequiredService<ILogger<MessageServer>>().LogWarning("The message server started!");
    }
    /// <summary>
    /// 应用服务器设置
    /// </summary>
    /// <param name="options"></param>
    /// <param name="setting"></param>
    public static void SetServerOptions(this HttpConnectionDispatcherOptions options, HostSetting setting)
    {
        options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling;
        if (setting.ApplicationMaxBufferSize.HasValue)
        {
            options.ApplicationMaxBufferSize = setting.ApplicationMaxBufferSize.Value;
        }

        if (setting.TransportMaxBufferSize.HasValue)
        {
            options.TransportMaxBufferSize = setting.TransportMaxBufferSize.Value;
        }

        if (setting.TransportSendTimeout.HasValue)
        {
            options.TransportSendTimeout = TimeSpan.FromSeconds(setting.TransportSendTimeout.Value);
        }
    }
}